package com.yunshan.oss;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectRequest;
import com.yunshan.common.exception.ServiceException;
import com.yunshan.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

/**
 * @description:
 * @author: lrx
 * @date: 2022/7/14 11:21
 * @version: v1.0
 * @change [修改时间] [修改者@][版本号] [修改内容]
 */
@Service
@Slf4j
public class OssFileService {
    @Resource
    private OssConfig alOssConfig;
    @Value("${aliyun.oss.bucketName}")
    private String BUCKET_NAME;
    @Value("${aliyun.oss.endpoint}")
    private String ALIYUN_OSS_ENDPOINT;
    @Value("${aliyun.oss.policy.expire}")
    private int ALIYUN_OSS_EXPIRE;
    @Value("${aliyun.oss.maxSize}")
    private int ALIYUN_OSS_MAX_SIZE;
    @Value("${aliyun.oss.callback}")
    private String ALIYUN_OSS_CALLBACK;
    @Value("${aliyun.oss.dir.prefix}")
    private String ALIYUN_OSS_DIR_PREFIX;


    /**
     * 获取签名
     * @return
     */
    public OssPolicyResult policy() {
        OSSClient ossClient =(OSSClient) alOssConfig.ossClient();
        OssPolicyResult result = new OssPolicyResult();
        // 存储目录
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dir = ALIYUN_OSS_DIR_PREFIX +sdf.format(new Date());
        // 签名有效期
        long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
        Date expiration = new Date(expireEndTime);
        // 文件大小
        long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
        // 回调
        OssCallbackParam callback = new OssCallbackParam();
        callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
        callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
        callback.setCallbackBodyType("application/x-www-form-urlencoded");
        // 提交节点
        String action =  ALIYUN_OSS_ENDPOINT.replace("https://", "https://" + BUCKET_NAME + ".");
        try {
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String policy = BinaryUtil.toBase64String(binaryData);
            String signature = ossClient.calculatePostSignature(postPolicy);
            String callbackData = BinaryUtil.toBase64String(JSONObject.toJSONString(callback.toString()).getBytes("utf-8"));
            // 返回结果
            result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
            result.setPolicy(policy);
            result.setSignature(signature);
            result.setDir(dir);
            result.setCallback(callbackData);
            result.setHost(action);
        } catch (Exception e) {
            log.error("签名生成失败", e);
        }
        return result;
    }



    public OssCallbackResult callback(HttpServletRequest request) {
        OssCallbackResult result= new OssCallbackResult();
        String filename = request.getParameter("filename");
        filename = "https://".concat(BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);
        result.setFilename(filename);
        result.setSize(request.getParameter("size"));
        result.setMimeType(request.getParameter("mimeType"));
        result.setWidth(request.getParameter("width"));
        result.setHeight(request.getParameter("height"));
        return result;
    }



    /**
     * 上传图片
     * @param prefix 前缀
     * @param name 名字可指定可不指定
     * @return {@link String} 返回的链接
     */
    public String uploadFile(String prefix, String name, MultipartFile file){
        if (StringUtil.isBlank(prefix)){
            throw new ServiceException("前缀必填例如：jvxi/img");
        }
        String fileExtension = getFileExtension(file);
        String contentType = getContentType(fileExtension);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(contentType);
        if (StringUtil.isBlank(name)){
            name = StringUtil.getUUID();
        }
        if (!prefix.endsWith("/")){
            prefix  = prefix +"/";
        }
        InputStream inputStream = null;
        String objectName = prefix + name  +fileExtension;
        try {
            inputStream = file.getInputStream();
            return getString(objectName, metadata, inputStream);
        }catch (Exception e) {
            log.error("文件上传失败：{}", e.getMessage());
            return "文件上传失败";
        }
    }

    /**
     *
     * @param prefix 前缀必填
     * @param name 名字可指定可不指定
     * @param base64Code 图片
     * @return {@link String} 返回的链接
     */
    public String uploadFile(String prefix , String name, String base64Code){
        if (StringUtil.isBlank(prefix)){
            throw new ServiceException("前缀必填例如：jvxi/img");
        }
        if (StringUtil.isBlank(name)) {
            name = StringUtil.getUUID();
        }
        if (!prefix.endsWith("/")) {
            prefix = prefix + "/";
        }
        String fileExtension = ".png";
        String objectName = prefix + name + fileExtension;
        String contentType = getContentType(fileExtension);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(contentType);
        InputStream inputStream = null;
        try {
            byte[] bytes = Base64.getDecoder().decode(base64Code);
            inputStream = new ByteArrayInputStream(bytes);
            return getString(objectName, metadata, inputStream);
        }catch (Exception e) {
            log.error("文件上传失败：{}，"+ e.getMessage());
            return "文件上传失败";
        }finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public String uploadFile(String prefix , String name,BufferedImage image){
        if (StringUtil.isBlank(prefix)){
            throw new ServiceException("前缀必填例如：jvxi/img");
        }
        if (StringUtil.isBlank(name)) {
            name = StringUtil.getUUID();
        }
        if (!prefix.endsWith("/")) {
            prefix = prefix + "/";
        }
        String fileExtension = ".png";
        String objectName = prefix + name + fileExtension;
        String contentType = getContentType(fileExtension);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(contentType);
        InputStream inputStream = null;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", os);
            inputStream = new ByteArrayInputStream(os.toByteArray());
            return getString(objectName, metadata, inputStream);
        } catch (Exception e){
            log.error("文件上传失败：{}，"+ e.getMessage());
            return "文件上传失败";
        }finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

    /**
     * 上传图片
     * @param objectName 地址
     * @param metadata 标签投
     * @param inputStream 输入流
     * @return 上传地址
     */
    private String getString(String objectName, ObjectMetadata metadata, InputStream inputStream) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME,
                objectName, inputStream, metadata);
        OSS ossClient = alOssConfig.ossClient();
        ossClient.putObject(putObjectRequest);
        String result = ALIYUN_OSS_ENDPOINT.replace("https://", "https://" + BUCKET_NAME + ".");
        result = result + "/" + objectName;
        return result;
    }


    /**
     * 获取后缀
     * @param cFile
     * @return
     */
    private String getFileExtension(MultipartFile cFile) {
        String originalFileName = cFile.getOriginalFilename();
        return originalFileName.substring(originalFileName.lastIndexOf("."));
    }

    /**
     * 设置Content-Type
     * @param FilenameExtension
     * @return
     */
    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }

}
